#include "comm.h"


#define DEBUG 1
#define DEFAULT_PORT 80

//now only support the HTTP

enum DOWNLOAD_TYPE {HTTP,FTP};

char filename[100];
char path[100];
char hostname[100];
int server_port;
int filesize;
int dtype;
int flag;
FILE *fp;

//multi-threads args
typedef struct T_ARGS{
	int offset;
	int sum;
}T_ARGS;

int getfilesize() 
{
	char send_buffer[1024];
	char recv_buffer[1024];
	//about the sock
	int result;
	int sockfd;
	struct sockaddr_in clientservice;
	struct hostent* remotehost;
	char size[10] = {0};
	int size_num = 0;
	
	sprintf(send_buffer, 
			"GET %s HTTP/1.1\r\nAccept: */*\r\nCache-Control: no-cache\r\nConnection: Keep-Alive\r\nHost: %s\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n\r\n",
			path,
			hostname);
	
	//if (DEBUG) {
	//	printf("%s\n",send_buffer);
	//}
	//create a socket
	sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	
	remotehost = gethostbyname(hostname);
	
	//IPaddress and port of the server to connected to .
	clientservice.sin_family = AF_INET;
	clientservice.sin_addr = *((struct in_addr*)remotehost->h_addr);
	clientservice.sin_port = htons(80);
	
	
	//connect the server
	result = connect(sockfd,(struct sockaddr *)&clientservice,sizeof(clientservice));
	if (result == -1)
	{
		printf("connect failed\n");
		close(sockfd);
		return 0;
	}
	//send the buffer
	result = send(sockfd,send_buffer,strlen(send_buffer),0);
	
	if (result == 0) {
		printf("send failed\n");
		close(sockfd);
		return 0;
	}
	
	//recv the data
	result = recv(sockfd,recv_buffer,1024,0);
	if (result > 10) {
		//if (DEBUG) {
		//	printf("%s\n",recv_buffer);
		//}
		//to check if the return value is 200
		if (strncmp(recv_buffer, "HTTP/1.1 200", 12) == 0 || strncmp(recv_buffer, "HTTP/1.0 200", 12) == 0) {
			//analy the size.
			char *pos,*pos2;
			pos = strstr(recv_buffer,"Content-Length: ");
			pos2 = strstr(pos,"\r\n");
			
			strncpy(size,pos+16,pos2-(pos+16));
			//change str into int
			size_num = atoi(size);
		}
		close(sockfd);
	} else if (result == 0){
		printf("Connection closed\n");
		close(sockfd);
	} else {
		printf("recv failed\n");
		close(sockfd);
	}
	
	return size_num;
}




//thread_download

void thread_download(T_ARGS *args) {
	
	char send_buffer[1024];
	char recv_buffer[1024];
	
	int offset,sum;
	offset = args->offset;
	sum = args->sum;
	
	int result;
	int sockfd;
	struct sockaddr_in clientservice;
	struct hostent* remotehost;
	
	pthread_mutex_t mutex;
	pthread_mutex_init(&mutex,NULL);
	
	//init the two buffer
	memset(send_buffer,0,1024);
	memset(recv_buffer,0,1024);
	
	sprintf(send_buffer, 
			"GET %s HTTP/1.1\r\nAccept: */*\r\nCache-Control: no-cache\r\nConnection: Keep-Alive\r\nHost: %s\r\nPragma: no-cache\r\nRange: bytes=%d-%d\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n\r\n",
			path,
			hostname,
			offset,
			offset + sum - 1);
	
	//if (DEBUG) {
	//	printf("%s\n",send_buffer);
	//}
	//create a socket
	sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	
	remotehost = gethostbyname(hostname);
	
	//IPaddress and port of the server to connected to .
	clientservice.sin_family = AF_INET;
	clientservice.sin_addr = *((struct in_addr*)remotehost->h_addr);
	clientservice.sin_port = htons(80);
	
	
	//connect the server
	result = connect(sockfd,(struct sockaddr *)&clientservice,sizeof(clientservice));
	if (result == -1)
	{
		printf("connect failed\n");
		close(sockfd);
		exit(0);
	}
	//send the buffer
	result = send(sockfd,send_buffer,strlen(send_buffer),0);
	
	if (result == 0) {
		printf("send failed\n");
		close(sockfd);
		exit(0);
	}
	
	//recv the data
	int flag = 0;
	int write_num = 0;
	while (1) {
		result = recv(sockfd,recv_buffer,1024,0);
		
		if (result > 0 ) {
			//get the data.then write the data to the file
			//if (DEBUG) {
			//	printf("%s\n",recv_buffer);
			//}
			if (strncmp(recv_buffer,"HTTP/1.1 206", 12) == 0 || strncmp(recv_buffer,"HTTP/1.0 206", 12) == 0 ) {
			
				char *pos;
				pos = strstr(recv_buffer,"\r\n\r\n");
				pos = pos +4;
				//write to the file use the thread lock
				pthread_mutex_lock(&mutex);
				write_num = result - (pos - recv_buffer);
				fseek(fp,offset,SEEK_SET);
				fwrite(pos,1,write_num,fp);
				offset += write_num;
				//remove the fp to the start
				fseek(fp, 0, SEEK_SET);
				write_num = 0;
				pthread_mutex_unlock(&mutex);
				flag = 1;
			} else if (flag == 1 ){
				
				pthread_mutex_lock(&mutex);
				fseek(fp,offset,SEEK_SET);
				fwrite(recv_buffer,1,result,fp);
				offset += result;
				//remove the fp to the start
				fseek(fp, 0, SEEK_SET);
				pthread_mutex_unlock(&mutex);
				
			} else { //flag = 0
				printf("recv error\n");
				break;
			}
			memset(recv_buffer,0,1024);
		} else if (result == 0) {
			printf("recv over\n");
			break;
		} else {
			printf("recv failed\n");
			break;
		}
	}
	
	close(sockfd);
}
void download(char * url, int type)
{
	//DOWNLOAD_TYPE = HTTP
	if (type == HTTP)
	{
		//analy url
		char* pos;
		char* pos1;
		char* pos2;
		char ports[6];
		//FILE *fp;
		
		pos = strrchr(url, '/');
		
		if (pos) {
			
			strncpy(filename,pos+1,url + strlen(url) - pos);
			pos1 = strchr(url,'/');
			strncpy(hostname,url,pos1-url);
			
			strncpy(path,pos1,url+strlen(url)-pos1);
			printf("\nbegain ...\n\n");
			printf("get %s from %s\n\n",filename,hostname);
			
			if (pos2 = strchr(url,':'))
			{
				if (pos1 - pos2 < 6) {
					strncpy(ports,pos2+1,pos1 - pos2);
					server_port = atoi(ports);
				}
			}
			if (server_port == 0 || server_port > 65535) {
				server_port = DEFAULT_PORT;
			}
			
			
			//now download this filename from hostname
			//first get the filesize.
			filesize = getfilesize();
			printf("filesize is %d\n\n",filesize);
			if (filesize > 0) {
				//then create three threads to download this file
				printf("use three threads to download %s ...\n\n",filename);
			
				//create a file with filesize size and use A to tianman
				
				
				
				fp = fopen(filename,"w+");
			
				pthread_t tid[3];
				int i;
				int offset[3],sum[3];
				offset[0] = 0;
				offset[1] = filesize/3;
				offset[2] = (filesize/3)*2;
				sum[0] = offset[1];
				sum[1] = offset[2] - offset[1];
				sum[2] = filesize - offset[2];
				
			
				//create three threads 
				T_ARGS arg[3];
				for (i = 0;i < 3; i ++) {
					
					arg[i].offset = offset[i];
					arg[i].sum = sum[i];

					pthread_create(&tid[i],NULL,(void*)thread_download,&arg[i]);
					//pthread_join(tid[i], NULL);
				}
				
				for (i = 0;i < 3; i ++) {
					pthread_join(tid[i], NULL);
				}
				
				//here check three threads going out .then close the fd.
				fclose(fp);
			}
			
		} else {
			printf("There is no file!\nPlese check again\n");
		}
	}
}

int main (int argc,char * argv[]) {
    // insert code here...
	
	
	// analy the url in the argv
	if (argc < 2)
	{
		printf("Usage: multi-download url\n");
		return 0;
	}
	char *url;
	//char url[1024] = {0}; 
	
	url = argv[1];
	if (strncmp(url,"http://",7) == 0)
	{
		dtype = HTTP;
		url = url+ 7;
	} else if (strncmp(url,"ftp://",6) == 0){
		dtype = FTP;
	}
	download(url,dtype);
    return 0;
}
